<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="js/socket.io.js"></script>
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <style>
    * {
      margin: 0;
      padding: 0;
      list-style: none;
      text-decoration: none;
    }
    html,
    body,
    #app {
      width: 100%;
      height: 100%;
    }
    #app {
      margin: 0 auto;
      text-align: center;
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
    }
    .title {
      margin-top: 10px;
    }
    .QRcode {
      margin-top: 20px;
      width: 240px;
      height: 240px;
      position: relative;
    }
    .QRcode_overtime {
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
      position: absolute;
      width: 100%;
      height: 100%;
      left: 0;
      top: 0;
      background: rgba(0, 0, 0, 0.68);
      color: #fff;
      text-align: center;
      z-index: 2;
      font-size: 18px;
      cursor: pointer;
    }
    .QRcode_overtime img {
      width: 40px;
      height: 40px;
      margin-top: 15px;
    }
    .QRcode_success {
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
      position: absolute;
      width: 100%;
      height: 100%;
      left: 0;
      top: 0;
      background: rgba(0, 0, 0, 0.68);
      color: #fff;
      text-align: center;
      z-index: 3;
      font-size: 18px;
    }
    .QRcode_success img {
      width: 40px;
      height: 40px;
      margin-bottom: 15px;
    }
    .QRcode_img {
      width: 100%;
      height: 100%;
      position: absolute;
      z-index: 1;
      left: 0;
      top: 0;
    }
    .info {
      color: #8d8d8d;
      margin-top: 10px;
    }
    .tips {
      margin-top: 10px;
      background: #8d8d8d;
      border-radius: 24px;
      padding: 4px 14px;
      font-size: 13px;
      color: #fff;
    }
    .WapEmpower button {
      margin-top: 20px;
    }
    .tips {
      margin-top: 20px;
    }
  </style>
</head>
<body>

  <div id="app">

    <a href='https://gitee.com/bmycode/ScanCodeLogin'>
      <img src='https://gitee.com/bmycode/ScanCodeLogin/widgets/widget_3.svg' alt='Fork me on Gitee'></img>
    </a>

    <h2 class="title">扫码登录 案例</h2>
    <p class="info">Nodejs + Redis + Socket + Mysql + Vue + Uni-app</p>
    <br>
    <el-tabs v-model="activeName" @tab-click="handleClick">
      <el-tab-pane label="移动端扫码登录" name="ScanCode">
        <div class="QRcode">
          <!--扫码成功的样式-->
          <div class="QRcode_success" v-if="successShow">
            <img src="./img/success.png" alt="success">
            <p>扫码成功</p>
          </div>
          <!--二维码失效的样式-->
          <div class="QRcode_overtime" @click="AgainScanCode" v-if="overtimeShow">
            <p>二维码失效，点击重新获取</p>
            <img src="./img/reload.png" alt="reload.png">
          </div>
          <!--真正让用户扫的二维码-->
          <img class="QRcode_img" :src="base64QRcode.QRcode">

        </div>
        <p class="tips">{{ tipsText }}</p>
      </el-tab-pane>
      <el-tab-pane label="移动端授权登录" name="WapEmpower">
        <div class="WapEmpower">
          <p>请点击【登录】按钮</p>
          <p>在移动端弹窗的页面中授权本次登录</p>
          <p class="tips" v-if="WapSuccess.length != 0">{{WapSuccess}}</p>
          <el-button type="success" @click="RequestLogin"> 登 录 </el-button>
        </div>
      </el-tab-pane>
    </el-tabs>

  </div>

</body>

<script>
  var app = new Vue({
    el: '#app',
    data: {
      socket: null,          // 保存 socket链接
      socketURL: 'http://192.168.0.133:9080',  // socket 服务的地址
      base64QRcode: '',      // 保存后端给的二维码和uuid
      timerCheck: null,      // 保存定时器
      tipsText: '请扫码',        // 提示文字
      overtimeShow: false,   // 是否显示二维码失效
      successShow: false,    // 是否显示扫码成功
      ScanCodeShow: false,   // 如果用户扫码了，那么不显示 等待用户扫码中 的提示文字
      activeName: 'ScanCode',// 保存当前tab的类型
      WapSuccess: ''         // 授权登录成功后的提示信息
    },
    created() {
      // 创建 Socket 链接
      this.socket = io.connect(this.socketURL);
      this.handleClick();
    },
    methods: {
      // 判断点击的是哪个tabs，默认激活调用 【移动端扫码登录】
      handleClick() {
        switch (this.activeName) {
          case "ScanCode":
            this.getQRcode();
            this.ScanCodeOvertime();
            this.ScanCodeing();
            break;
          case "WapEmpower":
            this.DoNotRepeatRequest();
            this.AuthorizedWebSuccess()
            break;
        }
      },
      // 请求移动端登录按钮被点击，检查用户是否已经扫码登录，有发送emit，没有提示
      RequestLogin() {
        localStorage.getItem("id") !== null
          ? this.socket.emit('WebRequestLogin', localStorage.getItem("id"))
          : this.$notify.error({ title: '提示', message: '请先扫码登录哦！' });
      },
      // 监听后端 emit， 重复点击 登录 按钮的提示
      DoNotRepeatRequest() {
        this.socket.on('DoNotRepeatRequest', res => {
          this.$notify.error({
            title: '提示',
            message: res
          });
        });
      },
      // 移动端成功授权web端登录的监听
      AuthorizedWebSuccess() {
        this.socket.on('AuthorizedWebSuccess', res => {
          this.WapSuccess = res
          console.log("移动端授权登录成功，用户信息为：", res)
        });
      },
      getQRcode() {
        // 向服务器要uuid和二维码
        this.socket.emit('getQRcode');
        this.sendQRcode();
      },
      // 接受服务器给的uuid和二维码
      sendQRcode() {
        this.socket.on('sendQRcode', res => this.base64QRcode = res);
        this.checkScanCode();
      },
      checkScanCode() {

        // 等待扫码
        this.socket.on('waitScanCode', res => {
          if (!this.ScanCodeShow) {
            this.tipsText = '等待用户扫码'
          }
        });

        // 扫码成功
        this.socket.on('SuccessScanCode', (res) => {
          localStorage.setItem("id", JSON.parse(res).id);
          //this.tipsText = `扫码成功用户信息为：${res}`;   // 提示信息
          this.successShow = true;                    // 显示扫码成功的样式
          clearInterval(this.timerCheck);             // 扫码成功，清除定时器，不再询问服务器
        });

        // 每1秒询问一次服务器，用户App端是否扫码
        this.timerCheck = setInterval(() => this.socket.emit("checkScanCode", this.base64QRcode.uuid),1000);

      },

      // 如果二维码超时
      ScanCodeOvertime() {
        this.socket.on('ScanCodeOvertime', () => {
          // 如果二维码已经失效，并且用户还未扫码的话，那么才去显示二维码失效的样式
          // 之所以在这判断一次的原因，因为如果用户扫码成功之后，二维码才失效
          // 页面上会显示二维码失效的样式，体验不好。
          if(!this.successShow) {
            console.log("【Vue端】：二维码超时");
            clearInterval(this.timerCheck); // 二维码失效，不再询问服务器
            this.overtimeShow = true;       // 显示二维码失效的样式
            this.tipsText = "二维码失效";     // 清空等待扫码文字
          }
        })
      },

      // 已扫码但未确认
      ScanCodeing() {
        this.socket.on('ScanCodeing', () => {
          this.ScanCodeShow = true;
          this.tipsText = "您已扫码，请在手机上确认登录！"
        })
      },

      // 二维码失效后，用户点击二维码重新获取二维码的事件
      AgainScanCode() {
        this.overtimeShow = false;
        this.ScanCodeShow = false;
        this.socket.emit('getQRcode');
        this.sendQRcode();
      }

    }
  })
</script>
</html>